<template>
  <PageWrapper>
    <!-- 笔记 -->
    <CollapseContainer class="mt-5" title="props">
      <markdown-viewer :value="getDoc()" />
    </CollapseContainer>

    <CollapseContainer class="mt-5" title="props 用法示例">

      <Grand/>

      <template #action>
        <Icon icon="ant-design:code-outlined" class="mr-1" :size="26" @click="openSource('基本类型', getBasic())" />
      </template>
    </CollapseContainer>

    <!-- 源码组件 -->
    <SourceDrawer ref="sourceDrawer" />
  </PageWrapper>
</template>
<script lang="ts" setup>
  import { CollapseContainer } from '@/components/Container';
  import { MarkdownViewer } from '@/components/Markdown';
  import { PageWrapper } from '@/components/Page';
  import SourceDrawer from '@/learn/SourceDrawer.vue';
  import { ref } from 'vue';
  import { Icon } from '@/components/Icon';
  import Grand from "./Grand.vue";

  // 定义子组件引用
  let sourceDrawer = ref<any>(null);
  function openSource(title: string, content: string) {
    sourceDrawer.value.open({ title, content, width: '60%' });
  }

</script>

<script lang="ts">
  function getDoc() {
    return `
* v-bind='$attrs' 和 props 用法非常类似，只是 props 实现的是 父传子，而 v-bind='$atrrs' 实现的是 祖传孙(可以无限向下传递)
  * 传递普通对象: 简单的值传递，子组件变更，父组件不会感知
  * 传递引用对象: 子组件内修改，父组件同步变更
  * 传递方法: 可以实现子传父的功能，子组件通过回调父组件方法，将子组件数据传递给父组件。类似于 emits
* 使用步骤:
  * 祖组件将要传递的元素，以绑定属性方式进行传递
  * 父组件:
    * 不能使用 defineProps 接收，接收的属性会从 $attrs 变量中移除。
    * 父组件在孙组件标签上，写上标准向下传递未接收的元素, 固定语法: v-bind='$attrs'
  * 孙组件: 和 props 用法一致
    * 子组件通过 defineProps([xx,xx]) 方法接收，如果未接收的存入 $attrs 变量中。
    * 子组件通过调用父组件传递的方法，实现将子组件的数据回传给父组件，或触发父组件的方法
    * 对 props 进行解构时，需要注意添加 toRefs，否则将失去响应式。
* 适用场景:
  * 列表 -> 新增/修改 -> 弹窗 场景
  * 二次封装 UI 库时，需要将自定义组件的标签上指定参数，然后传递给 UI 库中的属性。vben 中封装 antd 组件中大量用了此种写法
`;
  }

  function getBasic() {
    return `
### 祖-组件
\`\`\`html
<template>
  <div class="mt-5 bg-green-300 p-5" title="父组件" :can-expan="false">
    <h3>祖-组件</h3>
    <ul>
      <li>普通对象 name:{{ name }}</li>
      <li>响应对象 car:{{ car }}</li>
      <li>响应对象 aliasName:{{ name }}</li>
      <li>接收子回调数据:{{ data }}</li>
    </ul>

    <Father :name="name" :car="car" :setData="setData" ext="普通参数" :aliasName="name" />
  </div>
</template>

\<script lang="ts" setup\>
  import Father from './Father.vue';
  import { ref } from 'vue';

  // 普通对象: 不具有响应式
  let name: string = 'hello';

  // 响应对象: 孙组件修改同步修改
  let car = ref({
    brand: '奔驰',
    price: 20,
  });

  // 存储孙组件回调数据
  let data = ref();

  // 接受孙组件回调
  function setData(callBackData: string) {
    data.value = callBackData;
  }
\</script\>
\`\`\`

### 父-组件
\`\`\`html
<template>
  <div class="mt-5 bg-gray-300 p-5" title="父组件" :can-expan="false">
    <h3>父-组件</h3>
    <ul>
      <li>截胡一个属性 aliasName:{{ aliasName }}</li>
    </ul>

    <Child v-bind:="$attrs" />
  </div>
</template>

\<script lang="ts" setup\>
  import Child from './Child.vue';

  // 截胡一个属性
  defineProps(['aliasName']);

\</script\>
\`\`\`


### 孙-组件
\`\`\`html
<template>
  <div class="mt-5 bg-blue-200 p-5" title="子组件" :can-expan="false">
    <h3>孙-组件</h3>
    <ul>
      <li>props 接收到的参数, 普通对象 name:{{ name }} </li>
      <li>props 接收到的参数, 响应对象 car:{{ car }}</li>
      <li>$attrs 存储未使用props接收的参数: {{ $attrs }}</li>
      <li>解构品牌 brand: {{ brand }}<Button @click="changeBrand">修改</Button>, 祖同步修改</li>
      <li>
        <input v-model="inputData" />
        <Button @click="sendData">向祖组件发送数据</Button>
      </li>
    </ul>
  </div>
</template>

\<script lang="ts" setup\>
  import { Button } from '@/components/Button';
  import { ref,toRefs } from 'vue';

  // 定义要接收从父组件传来的哪些参数
  let props = defineProps(['name', 'car', 'setData']);

  // 解构品牌
  let { brand } = toRefs(props.car);

  // 输入框的值
  let inputData = ref();

  // 修改品牌，则子组件、父组件全部同步修改
  function changeBrand(){
    brand.value += '~';
  }

  // 向父组件
  function sendData() {
    props.setData(inputData.value);
  }
\</script\>
\`\`\`

`;
  }

</script>

<style lang="less" scoped>
  button {
    margin-left: 5px;
  }
</style>
